package com.bos.prop.controller;

import com.bos.dao.KabupatenDAO;
import com.bos.domain.Kabupaten;
import com.bos.editor.KabupatenEditor;
import com.bos.util.UrlUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;

import javax.validation.Valid;
import java.util.List;
import java.util.Map;

/**
 * Created by IntelliJ IDEA.
 * User: Latief
 * Date: 3/18/11
 * Time: 3:06 PM
 * To change this template use File | Settings | File Templates.
 */
@Controller
public class KabupatenController {

    private KabupatenDAO kabupatenDAO;
    private RestTemplate restTemplate;
    /*private Credentials credentials;*/


    /* --------------------- Getter and Setter ---------------------*/

    /*public Credentials getCredentials() {
        return credentials;
    }

    @Autowired
    public void setCredentials(Credentials credentials) {
        this.credentials = credentials;
        if (restTemplate != null) {
            CommonsClientHttpRequestFactory factory = (CommonsClientHttpRequestFactory) restTemplate.getRequestFactory();
            HttpClient client = factory.getHttpClient();
            client.getState().setCredentials(AuthScope.ANY, credentials);
        }
    }*/

    @Autowired
    public void setRestTemplate(RestTemplate restTemplate) {
        this.restTemplate = restTemplate;

//        if (credentials != null) {
//            CommonsClientHttpRequestFactory factory = (CommonsClientHttpRequestFactory) restTemplate.getRequestFactory();
//            HttpClient client = factory.getHttpClient();
//            client.getState().setCredentials(AuthScope.ANY, credentials);
//        }
    }

    @Autowired
    public void setKabupatenDAO(KabupatenDAO kabupatenDAO) {
        this.kabupatenDAO = kabupatenDAO;
    }

    /* -------------------------- Other Methods -------------------------- */

    @RequestMapping(value = "/kabupaten", method = RequestMethod.GET)
    public String index(ModelMap modelMap) {
        modelMap.addAttribute("kabMenuList", kabupatenDAO.getAll());
        modelMap.addAttribute("data", kabupatenDAO.getAll());

        return "kabupaten/index";
    }

    @RequestMapping(value = "/kabupaten/new", method = RequestMethod.GET)
    public String create(ModelMap modelMap) {
        Kabupaten kabupaten = new Kabupaten();
        modelMap.addAttribute("kabupaten", kabupaten);
        modelMap.addAttribute("kabMenuList", kabupatenDAO.getAll());

        return "kabupaten/create";
    }

    @RequestMapping(value = "/kabupaten", method = RequestMethod.POST)
    public String save(@Valid @ModelAttribute("kabupaten") Kabupaten kabupaten, BindingResult result, ModelMap modelMap) {
        List<Kabupaten> kabupatens = kabupatenDAO.getAll();
        modelMap.addAttribute("kabMenuList", kabupatens);

        if (kabupaten == null) throw new IllegalArgumentException("A Product is required");
        if (result.hasErrors() || !kabupatenHostValidator(kabupaten) || !UrlUtil.isHostsAvailable(kabupatens)) {
            modelMap.addAttribute("kabupaten", kabupaten);
            return "kabupaten/create";
        }

        //Siapkan data baru yang akan dikirim ke semua kabupatenOld
        String restError = "";

        //Ambila data host kabupaten
        List<Kabupaten> hosts = kabupatenDAO.getAll();

        //Kirim data kabupaten sebelumnya ke host baru. agar data di host baru sinkron kabupatennya dengan data propinsi.
        for (Kabupaten kabupatenOld : hosts) {

            Kabupaten kabupatenOldHttpEntity = new Kabupaten();
            kabupatenOldHttpEntity.setNama(kabupatenOld.getNama());
            kabupatenOldHttpEntity.setHost(kabupatenOld.getHost());
            kabupatenOldHttpEntity.setPort(kabupatenOld.getPort());
            HttpEntity<Kabupaten> oldHttpEntity = new HttpEntity<Kabupaten>(kabupatenOldHttpEntity);

            String hostUrl = UrlUtil.getKabupatenHostUrl(kabupaten) + "/kabupaten.json";
            try {
                ResponseEntity<Map> responseEntity = restTemplate.exchange(hostUrl, HttpMethod.POST, oldHttpEntity, Map.class);
                Map<String, Object> response = responseEntity.getBody();
                if (!(Boolean) response.get("success"))
                    restError += hostUrl + "\n";
            } catch (Exception e) {
                e.printStackTrace();
                restError += hostUrl + "\n";
            }
        }

        //Simpan ke database lokal
        kabupatenDAO.save(kabupaten);

        Kabupaten kabupatenHttpEntity = new Kabupaten();
        kabupatenHttpEntity.setNama(kabupaten.getNama());
        kabupatenHttpEntity.setHost(kabupaten.getHost());
        kabupatenHttpEntity.setPort(kabupaten.getPort());
        HttpEntity<Kabupaten> httpEntity = new HttpEntity<Kabupaten>(kabupatenHttpEntity);

        //Kirim data baru dengan json ke semua kabupatenOld.
        hosts.add(kabupaten);
        for (Kabupaten host : hosts) {
            String hostUrl = UrlUtil.getKabupatenHostUrl(host) + "/kabupaten.json";
            try {
                ResponseEntity<Map> responseEntity = restTemplate.exchange(hostUrl, HttpMethod.POST, httpEntity, Map.class);
                Map<String, Object> response = responseEntity.getBody();
                if (!(Boolean) response.get("success"))
                    restError += hostUrl + "\n";
            } catch (Exception e) {
                e.printStackTrace();
                restError += hostUrl + "\n";
            }
        }
        //atribute jika terjadi error saat melakukan penyimpanan ke database kabupaten.
        if (!restError.isEmpty())
            modelMap.addAttribute("restError", restError.trim());

        return "redirect:/kabupaten/" + kabupaten.getId();
    }

    @RequestMapping(value = "/kabupaten/{id}", method = RequestMethod.GET)
    public String show(ModelMap modelMap, @PathVariable("id") Kabupaten kabupaten) {
        modelMap.addAttribute("kabMenuList", kabupatenDAO.getAll());
        modelMap.addAttribute("data", kabupaten);

        return "kabupaten/show";
    }

    @RequestMapping(value = "/kabupaten/{id}/delete", method = RequestMethod.GET)
    public String delete(@PathVariable("id") Kabupaten kabupaten, ModelMap modelMap) {
        List<Kabupaten> kabupatens = kabupatenDAO.getAll();
        modelMap.addAttribute("kabMenuList", kabupatens);

        //Jika ada kabupatenOld yang tidak ada maka skip operasi
        if (!UrlUtil.isHostsAvailable(kabupatens))
            return "redirect:/bank";

        //Siapkan data yang akan dihapus ke semua kabupatenOld
        String restError = "";
        HttpEntity<Kabupaten> httpEntity = new HttpEntity<Kabupaten>(kabupaten);

        //Kirim data yang akan dihapus dengan json ke semua kabupatenOld.
        List<Kabupaten> hosts = kabupatenDAO.getAll();
        for (Kabupaten host : hosts) {
            String hostUrl = UrlUtil.getKabupatenHostUrl(host) + "/kabupaten/" + kabupaten.getId() + "/delete.json";
            try {
                ResponseEntity<Map> responseEntity = restTemplate.exchange(hostUrl, HttpMethod.GET, httpEntity, Map.class);
                Map<String, Object> response = responseEntity.getBody();
                if (!(Boolean) response.get("success"))
                    restError += hostUrl + "\n";
            } catch (Exception e) {
                e.printStackTrace();
                restError += hostUrl + "\n";
            }
        }
        //atribute jika terjadi error saat melakukan penghapusan data di tiap kabupatenOld.
        if (!restError.isEmpty())
            modelMap.addAttribute("restError", restError.trim());

        //Hapus data lokal setelahnya.
        kabupatenDAO.delete(kabupaten);

        return "redirect:/kabupaten";
    }


    @RequestMapping(value = "/kabupaten/{id}/edit", method = RequestMethod.GET)
    public String edit(ModelMap modelMap, @PathVariable("id") Kabupaten kabupaten) {
        modelMap.addAttribute("kabMenuList", kabupatenDAO.getAll());
        modelMap.addAttribute("kabupaten", kabupaten);

        return "kabupaten/edit";
    }

    @RequestMapping(value = "/kabupaten", method = RequestMethod.PUT)
    public String update(@Valid @ModelAttribute("kabupaten") Kabupaten kabupaten, BindingResult result, ModelMap modelMap) {
        List<Kabupaten> kabupatens = kabupatenDAO.getAll();
        modelMap.addAttribute("kabMenuList", kabupatens);

        if (kabupaten == null) throw new IllegalArgumentException("A Product is required");
        if (result.hasErrors() || !kabupatenHostValidator(kabupaten) || !UrlUtil.isHostsAvailable(kabupatens)) {
            modelMap.addAttribute("kabupaten", kabupaten);
            return "kabupaten/edit";
        }

        //Siapkan data baru yang akan dikirim ke semua kabupatenOld
        String restError = "";
        HttpEntity<Kabupaten> httpEntity = new HttpEntity<Kabupaten>(kabupaten);

        //Kirim data baru dengan json ke semua kabupatenOld.
        List<Kabupaten> hosts = kabupatenDAO.getAll();
        for (Kabupaten host : hosts) {
            String hostUrl = UrlUtil.getKabupatenHostUrl(host) + "/kabupaten.json";
            try {
                ResponseEntity<Map> responseEntity = restTemplate.exchange(hostUrl, HttpMethod.PUT, httpEntity, Map.class);
                Map<String, Object> response = responseEntity.getBody();
                if (!(Boolean) response.get("success"))
                    restError += hostUrl + "\n";
            } catch (Exception e) {
                e.printStackTrace();
                restError += hostUrl + "\n";
            }
        }
        //atribute jika terjadi error saat melakukan penyimpanan ke database kabupaten.
        if (!restError.isEmpty())
            modelMap.addAttribute("restError", restError.trim());

        //simpan ke database lokal setelah semua database di semua kabupatenOld lain dirubah.
        kabupatenDAO.merge(kabupaten);

        return "redirect:/kabupaten/" + kabupaten.getId();
    }

    /**
     * Cek kabupatenOld dan port dalam kabupaten dalam format penulisan yang benar atau bukan. Penulisan yang diijinkan adalah
     * penulisan ip address atau 'localhost'.
     *
     * @param kabupaten
     * @return true - jika penulisan port dan kabupatenOld benar. false jika salah.
     */
    private boolean kabupatenHostValidator(Kabupaten kabupaten) {
        // Kabupaten tidak boleh null
        if (kabupaten == null)
            return false;

        // kabupatenOld tidak boleh null dan port bernilai lebih dari nol
        if (kabupaten.getHost() == null || kabupaten.getPort() <= 0)
            return false;

        //cek penulisan kabupatenOld berupa 'localhost' atau ip address
        if (!kabupaten.getHost().equals("localhost") && !kabupaten.getHost().matches("\\d{1,3}[.]\\d{1,3}[.]\\d{1,3}[.]\\d{1,3}"))
            return false;

        return true;
    }

    @InitBinder
    protected void initBinder(WebDataBinder binder) throws Exception {
        binder.registerCustomEditor(Kabupaten.class, new KabupatenEditor(kabupatenDAO));
    }

}
